import { useVueFlow } from '@vue-flow/core'
import { ref, watch } from 'vue'

let id = 0

/**
 * @returns {string} - A unique id.
 */
function getId() {
  return `dndnode_${id++}`
}

/**
 * In a real world scenario you'd want to avoid creating refs in a global scope like this as they might not be cleaned up properly.
 * @type {{draggedType: Ref<string|null>, isDragOver: Ref<boolean>, isDragging: Ref<boolean>}}
 */
const state = {
  /**
   * The type of the node being dragged.
   */
  draggedType: ref(null),
  isDragOver: ref(false),
  isDragging: ref(false),
}

export default function useDragAndDrop() {
  const { draggedType, isDragOver, isDragging } = state

  const { addEdges,addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode,getViewport } = useVueFlow()

  watch(isDragging, (dragging) => {
    document.body.style.userSelect = dragging ? 'none' : ''
  })

  function onDragStart(event, data) {
    if (event.dataTransfer) {
      event.dataTransfer.setData('application/json', data)
      event.dataTransfer.effectAllowed = 'move'
    }

    draggedType.value = data
    isDragging.value = true

    document.addEventListener('drop', onDragEnd)
  }

  /**
   * Handles the drag over event.
   *
   * @param {DragEvent} event
   */
  function onDragOver(event) {
    event.preventDefault()

    if (draggedType.value) {
      isDragOver.value = true

      if (event.dataTransfer) {
        event.dataTransfer.dropEffect = 'move'
      }
    }
  }

  function onDragLeave() {
    isDragOver.value = false
  }

  function onDragEnd() {
    isDragging.value = false
    isDragOver.value = false
    draggedType.value = null
    document.removeEventListener('drop', onDragEnd)
  }

  /**
   * Handles the drop event.
   *
   * @param {DragEvent} event
   */
  function onDrop(event) {
    const position = screenToFlowCoordinate({
      x: event.clientX,
      y: event.clientY,
    })

    const nodeId = Date.now().toString()
    const newNode = {
      id: nodeId,
      type: 'special',
      position,
      data: {
        nodeName:  draggedType.value.complex?'':draggedType.value.label,
        nodeContent: ``,
        nodeTitle: draggedType.value.complex?draggedType.value.label:'',
        type: draggedType.value.value,
        icon: draggedType.value.icon,
        api: draggedType.value.api,
        nodeTypeList:draggedType.value.nodeTypeList,
        nodeDataSubList:[],
        knowledgeConclusionTag:'',
        conclusionId:'',
        nodeBindConclusionId:'',
        knowledgeConclusionId:'',
        knowledgeConclusionLabel:'',
        submitApi: draggedType.value.submitApi,
        outFlag:draggedType.value.outFlag,
        complex: draggedType.value.complex,
        inFlag:draggedType.value.inFlag,
        customWidth: draggedType.value.maxWidth,
        upFlag:draggedType.value.upFlag,
        downFlag:draggedType.value.downFlag,
        maxWidth:draggedType.value.maxWidth,
        config:draggedType.value.customConfig,
      } ,
    }

    const { off } = onNodesInitialized(() => {
      updateNode(nodeId, (node) => ({
        position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 },
      }))
      off()
    })

    addNodes(newNode)
  }
    function addNode(node,single,singleType) {
      let  draggedType =  node.data;

      const nodeId = Date.now().toString()
     let  newNode = {
        id:nodeId,
        type: 'special',
        position:{
          y:node.position.y+100,
          x:node.position.x+100
        },
        data: {
          nodeName: draggedType.nodeName,
          nodeContent: draggedType.nodeContent,
          nodeTitle: draggedType.nodeTitle,
          type: draggedType.type,
          icon: draggedType.icon,
          api: draggedType.api,
          submitApi: draggedType.submitApi,
          outFlag:draggedType.outFlag,
          inFlag:draggedType.inFlag,
          customWidth: draggedType.maxWidth,
          upFlag:draggedType.upFlag,
          downFlag:draggedType.downFlag,
          maxWidth:draggedType.maxWidth,
          config:draggedType.config,
          complex:node.data.complex,
          nodeTypeList:node.data.nodeTypeList,
          nodeDataSubList:node.data.nodeDataSubList.map(item => {return {...item,id:null}}),
          knowledgeConclusionTag:'',
          conclusionId:'',
          nodeBindConclusionId:'',
          knowledgeConclusionId:'',
          knowledgeConclusionLabel:''
        } ,
      }

    const { off } = onNodesInitialized(() => {
      updateNode(nodeId, (node) => ({
        position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 },
      }))
      off()
    })
    addNodes(newNode)
  }


  function addMultipleNode(node,position,singleType,edgeFlag,oldNode) {
    let  {x,y}= position
    const nodeId = Date.now().toString()
    let  edgeData=[];
    let  newNode = node.content.split('\n').filter(item=>item.trim()!=='').map((item, index) => {
      let id = nodeId+index;
      let  returnData = {
        id:id,
        type: 'special',
        position:{
          y:y,
          x:x
        },
        data: {
          nodeName: '',
          nodeContent: ``,
          nodeTitle: item,
          type: singleType.value,
          icon: singleType.icon,
          api: singleType.api,
          nodeTypeList:singleType.nodeTypeList,
          nodeDataSubList:[],
          knowledgeConclusionTag:'',
          conclusionId:'',
          nodeBindConclusionId:'',
          customWidth: singleType.maxWidth,
          knowledgeConclusionId:'',
          knowledgeConclusionLabel:'',
          submitApi: singleType.submitApi,
          outFlag:singleType.outFlag,
          complex: singleType.complex,
          inFlag:singleType.inFlag,
          upFlag:singleType.upFlag,
          downFlag:singleType.downFlag,
          maxWidth:singleType.maxWidth,
          config:singleType.customConfig,
        } ,
      }

      if (edgeFlag){

        const newEdge = {
          "source": oldNode.id,
          "sourceHandle": "right",
          "target": id,
          "targetHandle": "left",
          "id": id
        }
        edgeData.push(newEdge)

      }


      y+=100
      return returnData;
    });

    const { off } = onNodesInitialized(() => {
      updateNode(nodeId, (node) => ({
        position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 },
      }))

      off()
    })

    addNodes(newNode)
    onConnect(edgeData)
  }

  function onConnect(params) {
    addEdges(params)
  }



  let trimmInnerLatexSpaces = (text)=> {
    // 使用正则表达式匹配所有 $...$ 结构
    // \$ 匹配美元符号本身
    // (.*?) 捕获两个美元符号之间的任何字符，? 表示非贪婪匹配，以正确处理一行中多个公式的情况
    // g 表示全局匹配，即替换所有找到的实例
    return text.replace(/\$(.*?)\$/g, (match, content) => {
      // content 是捕获到的美元符号之间的内容
      // content.trim() 会移除 content 字符串两端的空白字符
      return `$${content.trim()}$`;
    });
  }



  let toMath =  (htmlString)=> {
  if (htmlString === undefined || htmlString === null || htmlString === '') {
    return ''
  }

  const newHtmlString = htmlString.replace(/^<p>/, '').replace(/<\/p>$/, '').replace(/<br\/>/g, '\n');

    const correctedText = trimmInnerLatexSpaces(newHtmlString);

  return window.markdownToHTML(correctedText, {
    htmlTags: true,
    copyToClipboard: true,
    include_table_html: true
  })
}

  return {
    toMath,
    draggedType,
    isDragOver,
    isDragging,
    onDragStart,
    onDragLeave,
    onDragOver,
    onDrop,
    addNode,
    addMultipleNode
  }
}
